#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/workqueue.h>
#include <asm/current.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/version.h>
#include <linux/input.h>

static int major = 0;
static struct class *hs0038_class;

ssize_t hs0038_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	unsigned int val;	
    int err;

	if (size != 4)
		return -EINVAL;
	wait_event_interruptible(hs0038_wq, has_data());
	get_data(&val);
	err = copy_to_user(buf, &val, 4);		
	return 4;
}

static struct file_operations hs0038_fops = {
    .owner = THIS_MODULE;
    .read = hs0038_read;
};

static int hs0038_driver_probe(struct platform_device *pdev)
{       
    struct input_dev hs0038_input_dev;

    major = register_chrdev(0, "hs0038", &hs0038_fops);
    hs0038_class = class_create(THIS_MODULE, "hs0038_CLASS");
    if (IS_ERR(hs0038_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "hs0038");
        return -66;
    }
    device_create(hs0038_class, NULL, MKDEV(major, 0), NULL, "hs0038");



	/* 输入系统的代码 */
	/* 参考: drivers\input\keyboard\gpio_keys.c */
	/* A. 分配input_dev */
	hs0038_input_dev = devm_input_allocate_device(&pdev->dev);

	/* B. 设置input_dev */
	hs0038_input_dev->name = "hs0038";
	hs0038_input_dev->phys = "hs0038";

	/* B.1 能产生哪类事件 */
	__set_bit(EV_KEY, hs0038_input_dev->evbit);
	__set_bit(EV_REP, hs0038_input_dev->evbit);
	
	/* B.2 能产生哪些事件 */
	//__set_bit(KEY_0, hs0038_input_dev->keybit);
	memset(hs0038_input_dev->keybit, 0xff, sizeof(hs0038_input_dev->keybit));
	
	/* C. 注册input_dev */
	input_register_device(hs0038_input_dev);


    return 0;
}

static int hs0038_driver_remove(struct platform_device *pdev)
{
    device_destroy(hs0038_class, MKDEV(major, 0));
    class_destroy(hs0038_class);
    unregister_chrdev(major, "hs0038");

    gpiod_get();
    return 0;
}

static const struct of_device_id hs0038_id[] = {
    { .compatible = "PB, hs0038"},
    { },
};

static struct platform_driver hs0038_driver_pdev = {
    .probe = hs0038_driver_probe;
    .remove = hs0038_driver_remove;
    .driver = {
        .name = "hs0038",
        .of_match_table = hs0038_id,
    };
};

static __init int hs0038_drv_init(void)
{
    platform_driver_register(&hs0038_driver_pdev);
    return 0;
}

static __exit void hs0038_drv_exit(void)
{
    platform_driver_unregister(&hs0038_driver_pdev);
}

module_init(hs0038_drv_init);
module_exit(hs0038_drv_exit);
MODULE_LICENSE("GPL");
